<?php

namespace Wap\Service;

class WechatService
{
    private $appid = '';
    private $appsecret = '';
    private $accessToken = '';

    public function __construct($appid, $appsecret)
    {
        $this->appid = $appid;
        $this->appsecret = $appsecret;
        $this->accessToken = S($appid . "_access_token");

        if (!$this->accessToken) {
            $this->accessToken = $this->getAccessToken();
            S($appid . "_access_token", $this->accessToken, 6300);
        }
    }

    public function getAccessToken($appid = '', $appsecret = '')
    {
        $appid = $this->appid;
        $appsecret = $this->appsecret;

        $uri = "https://api.weixin.qq.com/cgi-bin/token" . "?" . "appid=" . $appid . "&" . "secret=" . $appsecret . "&" . "grant_type=client_credential";
        $out = self::simpleGet($uri);
        $out = json_decode($out, 1);
        $token = isset($out['access_token']) ? $out['access_token'] : null;
        return $token;
    }

    public function buildWXJSApi()
    {
        $token = $this->accessToken;

        $api = array("ticket" => "", "sha1" => "", "timestamp" => time(), "noncestr" => "1234567890", "url" => "");

        $protocol = (!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off' || $_SERVER['SERVER_PORT'] == 443) ? "https://" : "http://";
        $api['url'] = "$protocol$_SERVER[HTTP_HOST]$_SERVER[REQUEST_URI]";
        $api['ticket'] = $this->getJSAPITicket($token);
        $wxOri = sprintf("jsapi_ticket=%s&noncestr=%s&timestamp=%s&url=%s", $api['ticket'], $api['noncestr'], $api['timestamp'], $api['url']);
        $api['sha1'] = sha1($wxOri);
        return $api;
    }

    public function getJSAPITicket($token)
    {
        $try = 3;
        $ticket = null;
        do {
            $try--;

            $uri = sprintf("https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token=%s&type=jsapi", $token);
            $res = $this->simpleGet($uri);
            $res = json_decode($res, 1);
            $ticket = isset($res['ticket']) ? $res['ticket'] : null;

            if ($res['errcode'] == 40001) {
                $token = $this->getAccessToken();
                $this->accessToken = $token;
                S($this->appid . "_access_token", $this->accessToken, 6300);
            }
        } while ($try);

        return $ticket;
    }

    public function getFollowStatus($openid)
    {
        $token = $this->accessToken;
        $followed = false;

        $try = 2;
        do {
            $try--;

            $res = $this->simpleGet("https://api.weixin.qq.com/cgi-bin/user/info" . "?" . "access_token=" . $token . "&" . "openid=" . $openid);
            $res = json_decode($res, 1);
            trace($res, '用户是否关注', 'INFO');
            if (isset($res['subscribe']) && $res['subscribe']) {
                $followed = true;
            } else {
                $followed = false;
            }

            if ($res['errcode'] == 40001) {
                $token = $this->getAccessToken();
                $this->accessToken = $token;
                S($this->appid . "_access_token", $this->accessToken, 6300);
            }

        } while ($try);

        return $followed;
    }


    public function buildOauthURI($url, $scope = "snsapi_base", $state = 'oauth')//should not here
    {
        $appid = $this->appid;
        $uri = "https://open.weixin.qq.com/connect/oauth2/authorize?appid=" . $appid . "&redirect_uri=" . urlencode($url) . "&response_type=code&scope=" . $scope . "&state=" . $state . "#wechat_redirect";
        return $uri;
    }

    public function snsapiUserInfoLink($url, $appid)
    {
        $uri = sprintf("https://open.weixin.qq.com/connect/oauth2/authorize?appid=%s&redirect_uri=%s&response_type=code&scope=snsapi_userinfo&state=STATE#wechat_redirect", $appid, urlencode($url));
        return $uri;
    }

    public function snsapiUserInfo($appid, $appsecret, $code)
    {
        $uri = sprintf("https://api.weixin.qq.com/sns/oauth2/access_token?appid=%s&secret=%s&code=%s&grant_type=authorization_code", $appid, $appsecret, $code);
        $out = self::simpleGet($uri);
        $out = json_decode($out, 1);
        if (!isset($out['access_token'])) {
            return -1;
        }

        $uri = sprintf("https://api.weixin.qq.com/sns/userinfo?access_token=%s&openid=%s&lang=zh_CN", $out['access_token'], $out['openid']);
        $out = self::simpleGet($uri);
        $out = json_decode($out, 1);
        if (!isset($out['openid'])) {
            return -2;
        }

        return $out;
    }

    public function snsapiBaseUser($code)
    {
        $uri = "https://api.weixin.qq.com/sns/oauth2/access_token?appid=" . $this->appid . "&secret=" . $this->appsecret . "&code=" . $code . "&grant_type=authorization_code";
        $exist = $this->simpleGet($uri);
        $exist = json_decode($exist, 1);
        $exist = isset($exist['openid']) ? $exist['openid'] : null;

        return $exist;
    }

    /*
    private function simpleGet( $url )
    {
        $ch = curl_init();
        curl_setopt( $ch, CURLOPT_URL, $url );
        curl_setopt( $ch, CURLOPT_RETURNTRANSFER, 1 );
        $out = curl_exec( $ch );
        curl_close( $ch );
        return $out;
    }*/

    private function simpleGet($url)
    {
        $ch = curl_init();
        curl_setopt($ch, CURLOPT_URL, $url);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
        curl_setopt($ch, CURLOPT_TIMEOUT, 500);
        curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, true);
        $out = curl_exec($ch);
        curl_close($ch);
        return $out;
    }

    public static function wechat_user_info($access_token, $openid)
    {
        $url = 'https://api.weixin.qq.com/cgi-bin/user/info?access_token=' . $access_token . '&openid=' . $openid . '&lang=zh_CN';
        $ch = curl_init();
        curl_setopt($ch, CURLOPT_URL, $url);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
        curl_setopt($ch, CURLOPT_TIMEOUT, 500);
        curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, true);
        curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 2);
        $out = curl_exec($ch);
        curl_close($ch);
        $res = json_decode($out, true);
        return $res;
    }
}
